package DataAccess;

import java.io.*;
import java.util.*;
import java.util.zip.*;

import BackGround.*;
import Element.*;
import Element.Geom.*;
import DistSys.*;
import DataAccess.Storage.*;
/**
 * Title:        iPAD
 * Description:
 * Copyright:    Copyright (c) 2002
 * Company:      ABB Inc.
 * @author Fangxing Li
 * @version 1.0
 */

public class BinaryFileAccessor {
  public static final int PRJ_MISC  = 0;
  public static final int LAYER     = 1;
  public static final int ZONE      = 2;
  public static final int SHADING   = 3;
  public static final int BG_IMAGE  = 4;
  public static final int BG_LINE   = 5;
  public static final int TMPLT     = 6;
  public static final int ACTV_TMPLT= 7;
  public static final int CMP       = 8;
  public static final int NUM_FILES = 9; //Total # of entries in PAD file
  public static final String[] ENTRY_NAMES = {
      "ProjectMisc",
      "Layers",
      "Zones",
      "Shadings",
      "BackgroundImages",
      "BackgrounLines",
      "Templates",
      "ActiveTemplates",
      "Components"
  };


  public BinaryFileAccessor() { }

  public void initProject( String fileName ) throws Exception{
      loadTemplateFromPadFile( fileName);

      //load active dft template & shading options
      FileInputStream fis = new FileInputStream(fileName);
      ZipInputStream zin = new ZipInputStream( fis );
      ZipEntry ze;
      for(int i=0; i< this.NUM_FILES; i++ ){
          ze = zin.getNextEntry( );
          String sEntryName = ze.getName(); //this.ENTRY_NAMES[i]; //
          ObjectInputStream ois = new ObjectInputStream( zin );
          if( sEntryName.equalsIgnoreCase (ENTRY_NAMES[ACTV_TMPLT]) ){
              readEntry( sEntryName, ois);
          } else if( sEntryName.equalsIgnoreCase (ENTRY_NAMES[SHADING]) ){
              readEntry( sEntryName, ois);
          }
          //skip all other stuff
          zin.closeEntry();
      }
      zin.close();
  }

  public void saveToFile( String sPadFileName )throws Exception{
      String sPadFileNameWithoutExt ="";

      int sz;
      SysConst.progress =0;
      Sys.clearSelectionAndFocus();

      FileOutputStream fos = new FileOutputStream( sPadFileName );
      ZipOutputStream zout = new ZipOutputStream( fos );
      ZipEntry ze;

      for(int i=0; i< this.NUM_FILES; i++){
          ze = new ZipEntry( ENTRY_NAMES[i] );
          zout.putNextEntry(ze);
          ObjectOutputStream oos = new ObjectOutputStream( zout );
          writeEntry( i, oos );
          oos.flush();
          zout.closeEntry();
      }//end of for loop
      zout.close();
      SysConst.progress =20; //totally done
  }

  /**
   * When serialization multiple objects (of the same class), each must be
   * constructed individually.  Otherwise, only one object will be serialized.
   */
  private void writeEntry( int i, ObjectOutputStream oos ) throws Exception{
      int sz;
      if (i== this.PRJ_MISC){
          PrjMiscForStorage pm = new PrjMiscForStorage();
          pm.copyFromSysInMem();
          oos.writeObject( pm );
      } else if (i == this.LAYER ){
          sz = Sys.prjInfo.layerList.size();
          oos.writeInt(sz);
          Layer lyr;
          LayerForStorage lyrForStorage;
          for(int j=0; j<sz; j++){
              lyr = (Layer) Sys.prjInfo.layerList.get(j);
              lyrForStorage = new LayerForStorage();
              lyrForStorage.copyFromLayer( lyr );
              oos.writeObject( lyrForStorage );
          }
      } else if (i == this.ZONE ){
          sz = Sys.prjInfo.allZone.size();
          oos.writeInt(sz);
          Zone zone;
          ZoneForStorage zoneForStorage;
          for(int j=0; j<sz; j++){
              zone = (Zone) Sys.prjInfo.allZone.get(j);
              zoneForStorage = new ZoneForStorage();
              zoneForStorage.copyFromZone( zone );
              oos.writeObject( zoneForStorage );
          }
      } else if (i == this.SHADING ){
          sz = Sys.prjInfo.storedShadingOptions.size();
          oos.writeInt(sz);
          ShadingOption so;
          ShadingForStorage shadingForStorage;
          for(int j=0; j<sz; j++){
              so = (ShadingOption) Sys.prjInfo.storedShadingOptions.get(j);
              shadingForStorage = new ShadingForStorage();
              shadingForStorage.copyFromShadingOption( so );
              oos.writeObject( shadingForStorage );
          }
      }else if (i == this.BG_IMAGE ){
          sz = Sys.imgList.size();
          oos.writeInt(sz);
          BgImage bgImage;
          BgImageForStorage bgImageForStorage;
          for(int j=0; j<sz; j++){
              bgImage = (BgImage) Sys.imgList.get(j);
              bgImageForStorage = new BgImageForStorage();
              bgImageForStorage.copyFromBgImage( bgImage );
              oos.writeObject( bgImageForStorage );
          }
      } else if (i == this.BG_LINE ){
          sz = Sys.bgElemList.size();
          oos.writeInt(sz);
          BgLine bgLine;
          BgLineForStorage bgLineForStorage;
          for(int j=0; j<sz; j++){
              bgLine = (BgLine) Sys.bgElemList.get(j);
              bgLineForStorage = new BgLineForStorage();
              bgLineForStorage.copyFromBgLine( bgLine );
              oos.writeObject( bgLineForStorage );
          }
      } else if (i == this.TMPLT ){
          sz = Templates.allList.size();
          oos.writeInt(sz);
          AbsElem dftElem;
          ElemForStorage elemForStorage;
          for(int j=0; j<sz; j++){
              dftElem = (AbsElem) Templates.allList.get(j);
              elemForStorage = new ElemForStorage();
              elemForStorage.copyFromElem( dftElem, true );
              oos.writeObject( elemForStorage );
          }
      } else if (i == this.ACTV_TMPLT ){
          ActiveElemForStorage activeElemForStorage = new ActiveElemForStorage();
          activeElemForStorage.copyFromActiveTemp();
          oos.writeObject( activeElemForStorage );
      } else if (i == this.CMP ){
          sz = Sys.elemList.size();
          oos.writeInt(sz);
          AbsElem elem;
          ElemForStorage elemForStorage;
          for(int j=0; j<sz; j++){
              elem = (AbsElem) Sys.elemList.get(j);
              elemForStorage = new ElemForStorage();
              elemForStorage.copyFromElem( elem, false );
              oos.writeObject( elemForStorage );
          }
      }
  }//end of writeEntry

  public void loadFromFile( String fileName )throws Exception{
      SysConst.progress =0;
      FileInputStream fis = new FileInputStream(fileName);
      ZipInputStream zin = new ZipInputStream( fis );
      ZipEntry ze;

      Sys.reset();        //preventative redundency
      Templates.reset();  //preventative redundency

      for(int i=0; i< this.NUM_FILES; i++ ){
          ze = zin.getNextEntry( );
          String sEntryName = ze.getName(); //this.ENTRY_NAMES[i]; //
          ObjectInputStream ois = new ObjectInputStream( zin );
          readEntry( sEntryName, ois);
          zin.closeEntry();
      }
      zin.close();
      SysConst.progress =20; //totally done
  }

  private void readEntry(String sEntryName, ObjectInputStream ois ) throws Exception{
      int sz=-1;
      if ( sEntryName.equalsIgnoreCase( ENTRY_NAMES[ PRJ_MISC] )){
          PrjMiscForStorage pm = (PrjMiscForStorage) ois.readObject();
          pm.copyToSysInMem();
      } else if (sEntryName.equalsIgnoreCase( ENTRY_NAMES[LAYER]) ){
          sz = ois.readInt( );
          LayerForStorage lyrForStorage;
          Layer lyr ;
          for(int j=0; j<sz; j++){
              lyrForStorage = (LayerForStorage) ois.readObject();
              lyr = lyrForStorage.createLayerFromThis();
              //replacement for init layer list.
              int id = lyr.getIndex();
              id += ProjectInfo.NUM_BACK_GND_LAYER;
              if( id >=0 && id <ProjectInfo.NUM_LAYER ){
                  Layer layerInSys = (Layer) Sys.prjInfo.layerList.get( id );
                  layerInSys.setName( lyr.getName());
                  layerInSys.setMode( lyr.getMode());
                  layerInSys.setEngine( lyr.getEngine() ); //not really used.
              }
          }
      } else if (sEntryName.equalsIgnoreCase( ENTRY_NAMES[ZONE]) ){
          sz = ois.readInt( );
          ZoneForStorage zoneForStorage;
          Zone zone;
          for(int j=0; j<sz; j++){
              zoneForStorage = (ZoneForStorage) ois.readObject();
              zone = zoneForStorage.createZoneFromThis();
              Sys.prjInfo.addZoneIfUnexisted( zone );
          }
      } else if (sEntryName.equalsIgnoreCase( ENTRY_NAMES[SHADING]) ){
          sz = ois.readInt( );
          ShadingForStorage shadingForStorage;
          ShadingOption so;
          for(int j=0; j<sz; j++){
              shadingForStorage = (ShadingForStorage) ois.readObject();
              so = shadingForStorage.createShadingOptionFromThis();
              Sys.prjInfo.storedShadingOptions.add( so );
          }
      } else if (sEntryName.equalsIgnoreCase( ENTRY_NAMES[BG_IMAGE]) ){
          sz = ois.readInt( );
          BgImageForStorage bgImageForStorage;
          BgImage bgImage;
          for(int j=0; j<sz; j++){
              bgImageForStorage = (BgImageForStorage) ois.readObject();
              bgImage = bgImageForStorage.createBgImageFromThis();
              Sys.imgList.add( bgImage );
          }
      } else if (sEntryName.equalsIgnoreCase( ENTRY_NAMES[BG_LINE]) ){
          sz = ois.readInt( );
          BgLineForStorage bgLineForStorage;
          BgLine bgLine;
          for(int j=0; j<sz; j++){
              bgLineForStorage = (BgLineForStorage) ois.readObject();
              bgLine = bgLineForStorage.createBgLineFromThis();
              Sys.bgElemList.add( bgLine );
          }
      } else if (sEntryName.equalsIgnoreCase( ENTRY_NAMES[TMPLT]) ){
          sz = ois.readInt();
          AbsElem dftElem;
          ElemForStorage elemForStorage;
          for(int j=0; j<sz; j++){
              elemForStorage = (ElemForStorage) ois.readObject();
              dftElem = elemForStorage.createElemFromThis(true);
              Templates.insertIntoWithReplaceTempList(dftElem);
          }
          Templates.createSubList();                  //IMPORTANT
      } else if (sEntryName.equalsIgnoreCase( ENTRY_NAMES[ACTV_TMPLT]) ){
          ActiveElemForStorage activeElemForStorage =
              (ActiveElemForStorage) ois.readObject();
          activeElemForStorage.copyToActiveTempFromThis();
      } else if (sEntryName.equalsIgnoreCase( ENTRY_NAMES[CMP]) ){
          sz = ois.readInt( );
          AbsElem elem;
          ElemForStorage elemForStorage;
          Vector vEFS = new Vector( sz);
          for(int j=0; j<sz; j++){
              elemForStorage = (ElemForStorage) ois.readObject();
              vEFS.add(elemForStorage);
              elem = elemForStorage.createElemFromThis( false );
              elem.setDftTemp( elem.getDftTempName() ); //IMPORTANT!
              Sys.elemList.add( elem );
          }
          //get connectivity info.
          AbsElemGeom geom;
          for(int j=0; j<sz; j++){
              elem = (AbsElem) Sys.elemList.get(j);
              geom = elem.getElemGeomObj();
              elemForStorage = (ElemForStorage)vEFS.get(j);
              DBAccessor.extractConnFromString( geom.conn1, elemForStorage.getConn1() );
              DBAccessor.extractConnFromString( geom.conn2, elemForStorage.getConn2() );
              if( geom instanceof ThreeNodeElemGeom ){
                  DBAccessor.extractConnFromString(
                      ((ThreeNodeElemGeom)geom).conn3, elemForStorage.getConn3() );
              }
          }
      }
  }//end of readEntry();

  /**
   * Return a list of templates which have been updated or added into
   * Templates.allList.
   * Note: when we import templates, a new template will replace an old one
   * if they have the same name, or will be appended to Templates.allList
   * if the new template is not included in Templates.allList.
   */
  static public Vector loadTemplateFromPadFile( String fileName )throws Exception{
      Vector vTmp = new Vector(100,100);
      Vector vRtn = new Vector(100,100);
      int sz;
      int unitForTmp=0;
      SysConst.progress =0;
      FileInputStream fis = new FileInputStream(fileName);
      ZipInputStream zin = new ZipInputStream( fis );
      ZipEntry ze;

      for(int i=0; i< NUM_FILES; i++ ){
          ze = zin.getNextEntry( );
          String sEntryName = ze.getName();
          ObjectInputStream ois = new ObjectInputStream( zin );
          if( sEntryName.equalsIgnoreCase( ENTRY_NAMES[PRJ_MISC] ) ){
              PrjMiscForStorage pm = (PrjMiscForStorage) ois.readObject();
              unitForTmp = pm.getUnitOfLength();
          } else if( sEntryName.equalsIgnoreCase( ENTRY_NAMES[TMPLT] )){
              sz = ois.readInt();
              AbsElem dftElem;
              ElemForStorage elemForStorage;
              for(int j=0; j<sz; j++){
                  elemForStorage = (ElemForStorage) ois.readObject();
                  dftElem = elemForStorage.createElemFromThis(true);
                  vTmp.add( dftElem);
              }
              SysConst.progress = 10;
          }
          zin.closeEntry();
      }//end of for loop to scan all entries
      zin.close();

      //synchronize units for vTmp with Sys
      if( Sys.prjInfo.unitOfLength != unitForTmp ){
          double k=Sys.findRatioBtwnUnits( Sys.prjInfo.unitOfLength, unitForTmp);
          Templates.divideDataInPerUnitForVector(vTmp, k);
      }

      AbsElem elem, elem2;
      for(int i=0;i<vTmp.size();i++){
          elem = (AbsElem) vTmp.elementAt(i);
          elem2 = Templates.insertIntoWithReplaceTempList( elem );
          vRtn.add( elem2 );
      }
      Templates.createSubList();

      SysConst.progress =20; //totally done
      return vRtn;
  }//end of loadTemplateFromPadFile(String )

  public int importZoneFromProject(String fileName, double dImportedZone )throws Exception{
      int sz;
      int cntr=0; //to be returned
      int unitForTmp=0;
      Vector vTmp = null;

      SysConst.progress =0;
      Sys.clearSelectionAndFocus();

      FileInputStream fis = new FileInputStream(fileName);
      ZipInputStream zin = new ZipInputStream( fis );
      ZipEntry ze;

      for(int i=0; i< this.NUM_FILES; i++ ){
          ze = zin.getNextEntry( );
          String sEntryName = ze.getName();
          ObjectInputStream ois = new ObjectInputStream( zin );
          if( sEntryName.equalsIgnoreCase( ENTRY_NAMES[PRJ_MISC] ) ){
              PrjMiscForStorage pm = (PrjMiscForStorage) ois.readObject();
              unitForTmp = pm.getUnitOfLength();
          } else if( sEntryName.equalsIgnoreCase( ENTRY_NAMES[ZONE] )){
              sz = ois.readInt();
              for(int j=0; j<sz; j++){
                  ZoneForStorage zoneForStorage = (ZoneForStorage) ois.readObject();
                  Zone zone = zoneForStorage.createZoneFromThis();
                  if( zone.getZoneNumber()==dImportedZone ||
                      dImportedZone==Zone.ENTIRE_SYSTEM){
                          Sys.prjInfo.addZoneIfUnexisted( zone );
                  }
              }
              SysConst.progress = 2;
          } else if( sEntryName.equalsIgnoreCase( ENTRY_NAMES[CMP] )) {
              sz = ois.readInt( );
              vTmp = new Vector(sz);
              ElemForStorage elemForStorage;
              AbsElem elem;
              double dElemZone;
              for(int j=0; j<sz; j++){
                  elemForStorage = (ElemForStorage) ois.readObject();
                  elem = elemForStorage.createElemFromThis( false );
                  dElemZone = elem.getData(AbsElem.DATA_ZONE);
                  if( dImportedZone==dElemZone || dImportedZone==Zone.ENTIRE_SYSTEM ){
                      Sys.addElem( elem, false, true);
                      vTmp.add( elem );
                      cntr++;
                  }
                  SysConst.progress = 2 + (int) Math.round(17.0*i/sz); //at most 19
              }
          }
          zin.closeEntry();
      }//end of for loop to scan all entries
      zin.close();

      if( Sys.prjInfo.unitOfLength != unitForTmp ){
          double k=Sys.findRatioBtwnUnits( Sys.prjInfo.unitOfLength, unitForTmp);
          Sys.multiplyLengthForVector( vTmp, k);
          Sys.divideDataInPerUnitForVector( vTmp, k);
      }

      SysConst.progress =20; //totally done
      return cntr;
  }//end of importZoneFromProject(String fileName, double dImportedZone )


}
